Conversation
Summary: 'report_decode_errors' property missing from RialtoMSEVideoSink
Type: Feature
Test Plan: UT/CT, Fullstack
Jira: RDKEMW-12692
…linemodule.proto
Summary: 'report_decode_errors' property missing from RialtoMSEVideoSink
Type: Feature
Test Plan: UT/CT, Fullstack
Jira: RDKEMW-12692
Summary: 'report_decode_errors' property missing from RialtoMSEVideoSink
Type: Feature
Test Plan: UT/CT, Fullstack
Jira: RDKEMW-12692
Summary: 'report_decode_errors' property missing from RialtoMSEVideoSink
Type: Feature
Test Plan: UT/CT, Fullstack
Jira: RDKEMW-12692
|
Pull request must be merged with a description containing the required fields, Summary: If there is no jira releated to this change, please put 'Jira: NO-JIRA'. Description can be changed by editing the top comment on your pull request and making a new commit. |
|
All contributors have signed the CLA ✍️ ✅ |
There was a problem hiding this comment.
Pull request overview
This pull request adds support for the 'report_decode_errors' property for RialtoMSEVideoSink by implementing a complete feature path from client to GStreamer player. The feature allows enabling or disabling decode error reporting for video sources.
Changes:
- Added
setReportDecodeErrorsAPI across all layers (client IPC, server service, and GStreamer player) - Implemented SetReportDecodeErrors task in the GStreamer player task system
- Added protocol buffer definitions for setReportDecodeErrors RPC and GetQueuedFrames RPC (the latter appears unimplemented)
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| proto/mediapipelinemodule.proto | Added ReportDecodeErrors and GetQueuedFrames message definitions and RPC methods |
| media/public/include/IMediaPipeline.h | Added setReportDecodeErrors interface method |
| media/client/main/include/MediaPipeline.h | Added setReportDecodeErrors method declaration |
| media/client/main/include/MediaPipelineProxy.h | Added setReportDecodeErrors proxy method |
| media/client/main/source/MediaPipeline.cpp | Implemented client-side setReportDecodeErrors |
| media/client/ipc/interface/IMediaPipelineIpc.h | Added IPC interface for setReportDecodeErrors |
| media/client/ipc/include/MediaPipelineIpc.h | Added IPC implementation method declaration |
| media/client/ipc/source/MediaPipelineIpc.cpp | Implemented IPC client for setReportDecodeErrors |
| media/server/ipc/include/MediaPipelineModuleService.h | Added server IPC method declaration |
| media/server/ipc/source/MediaPipelineModuleService.cpp | Implemented server IPC handler |
| media/server/service/include/IMediaPipelineService.h | Added service interface method |
| media/server/service/source/MediaPipelineService.h | Added service method declaration |
| media/server/service/source/MediaPipelineService.cpp | Implemented service-layer routing |
| media/server/main/include/MediaPipelineServerInternal.h | Added server internal method declarations |
| media/server/main/source/MediaPipelineServerInternal.cpp | Implemented main thread coordination |
| media/server/gstplayer/interface/IGstGenericPlayer.h | Added GStreamer player interface method |
| media/server/gstplayer/include/IGstGenericPlayerPrivate.h | Added private interface for worker thread |
| media/server/gstplayer/include/GstGenericPlayer.h | Added method declarations |
| media/server/gstplayer/source/GstGenericPlayer.cpp | Implemented GStreamer player methods |
| media/server/gstplayer/include/tasks/IGenericPlayerTaskFactory.h | Added task factory interface for SetReportDecodeErrors |
| media/server/gstplayer/include/tasks/generic/GenericPlayerTaskFactory.h | Added task factory method declaration |
| media/server/gstplayer/source/tasks/generic/GenericPlayerTaskFactory.cpp | Implemented task factory method |
| media/server/gstplayer/include/tasks/generic/SetReportDecodeErrors.h | New task class header |
| media/server/gstplayer/source/tasks/generic/SetReportDecodeErrors.cpp | New task class implementation |
| media/server/gstplayer/CMakeLists.txt | Added SetReportDecodeErrors.cpp to build |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * This method is asynchronous, it will set the "Report Decode Errors" property | ||
| * | ||
| * @param[in] sourceId : The source id. Value should be set to the MediaSource.id returned after attachSource() | ||
| * @param[in] immediateOutput : Set Report Decode Errors mode on the sink |
There was a problem hiding this comment.
The parameter name in the documentation is incorrect. It should be "reportDecodeErrors" instead of "immediateOutput" to match the actual parameter name.
| * @param[in] immediateOutput : Set Report Decode Errors mode on the sink | |
| * @param[in] reportDecodeErrors : Set Report Decode Errors mode on the sink |
| * This method is asynchronous, it will set the "Report Decode Errors" property | ||
| * | ||
| * @param[in] sourceId : The source id. Value should be set to the MediaSource.id returned after attachSource() | ||
| * @param[in] immediateOutput : Set Report Decode Errors mode on the sink |
There was a problem hiding this comment.
The parameter name in the documentation is incorrect. It should be "reportDecodeErrors" instead of "immediateOutput" to match the actual parameter name.
| * @param[in] immediateOutput : Set Report Decode Errors mode on the sink | |
| * @param[in] reportDecodeErrors : Set Report Decode Errors mode on the sink |
| * @brief Creates a setReportDecodeErrors task. | ||
| * | ||
| * @param[in] context : The GstPlayer context | ||
| * @param[in] player : The GstPlayer instance | ||
| * @param[in] type : The media source type | ||
| * @param[in] immediateOutput : the value to set for report decode error | ||
| * | ||
| * @retval the new ProcessAudioGap task instance. |
There was a problem hiding this comment.
The return value documentation is incorrect. It should describe what task instance is being returned (SetReportDecodeErrors task) rather than stating "the new ProcessAudioGap task instance". This appears to be copy-pasted from another method without being updated.
| * @brief Creates a setReportDecodeErrors task. | |
| * | |
| * @param[in] context : The GstPlayer context | |
| * @param[in] player : The GstPlayer instance | |
| * @param[in] type : The media source type | |
| * @param[in] immediateOutput : the value to set for report decode error | |
| * | |
| * @retval the new ProcessAudioGap task instance. | |
| * @brief Creates a SetReportDecodeErrors task. | |
| * | |
| * @param[in] context : The GstPlayer context | |
| * @param[in] player : The GstPlayer instance | |
| * @param[in] type : The media source type | |
| * @param[in] reportDecodeErrors: the value to set for report decode errors | |
| * | |
| * @retval the new SetReportDecodeErrors task instance. |
| #ifndef FIREBOLT_RIALTO_SERVER_TASKS_GENERIC_SET_REPORT_DECODE_ERROR_H_ | ||
| #define FIREBOLT_RIALTO_SERVER_TASKS_GENERIC_SET_REPORT_DECODE_ERROR_H_ |
There was a problem hiding this comment.
The header guard name is inconsistent. It uses "SET_REPORT_DECODE_ERROR_H_" (singular) but should be "SET_REPORT_DECODE_ERRORS_H_" (plural) to match the class name SetReportDecodeErrors and follow the naming convention seen in other files.
| }; | ||
| } // namespace firebolt::rialto::server::tasks::generic | ||
|
|
||
| #endif // FIREBOLT_RIALTO_SERVER_TASKS_GENERIC_SET_REPORT_DECODE_ERROR_H_ |
There was a problem hiding this comment.
The header guard name is inconsistent. It uses "SET_REPORT_DECODE_ERROR_H_" (singular) but should be "SET_REPORT_DECODE_ERRORS_H_" (plural) to match the class name SetReportDecodeErrors and follow the naming convention seen in other files.
| /** | ||
| * @fn void getQueuedFrames(int session_id, int source_id, uint32_t &queued_frames) | ||
| * @brief Gets the "Queued Frames" property for this source. | ||
| * | ||
| * @param[in] session_id The id of the A/V session. | ||
| * @param[in] source_id The id of the media source. | ||
| * @param[out] queued_frames Get queued frames on the decoder | ||
| * | ||
| */ | ||
| message GetQueuedFramesRequest { | ||
| optional int32 session_id = 1 [default = -1]; | ||
| optional int32 source_id = 2 [default = -1]; | ||
| } | ||
| message GetQueuedFramesResponse { | ||
| optional uint32 queued_frames = 1 [default = -1]; | ||
| } |
There was a problem hiding this comment.
The GetQueuedFramesRequest and GetQueuedFramesResponse message definitions are added but there is no corresponding implementation in the server IPC layer, service layer, or client. This appears to be an incomplete feature addition. Either the implementation should be provided or these proto definitions should be removed.
| if (m_type != MediaSourceType::VIDEO) | ||
| { | ||
| RIALTO_SERVER_LOG_ERROR("SetReportDecodeErrors not currently supported for non-video"); | ||
| } | ||
|
|
||
| if (m_context.pipeline) | ||
| { | ||
| m_player.setReportDecodeErrors(m_reportDecodeErrors); | ||
| } |
There was a problem hiding this comment.
The function logs an error when the media source type is not VIDEO but continues execution and calls m_player.setReportDecodeErrors anyway. This appears to be a logic error. If the feature is not supported for non-video sources, the function should return early after logging the error, similar to how validation is typically handled.
| * @param[in] context : The GstPlayer context | ||
| * @param[in] player : The GstPlayer instance | ||
| * @param[in] type : The media source type | ||
| * @param[in] immediateOutput : the value to set for report decode error |
There was a problem hiding this comment.
The parameter name in the documentation is incorrect. It should be "reportDecodeErrors" instead of "immediateOutput" to match the actual parameter name.
| * @param[in] context : The GstPlayer context | |
| * @param[in] player : The GstPlayer instance | |
| * @param[in] type : The media source type | |
| * @param[in] immediateOutput : the value to set for report decode error | |
| * @param[in] context : The GstPlayer context | |
| * @param[in] player : The GstPlayer instance | |
| * @param[in] type : The media source type | |
| * @param[in] reportDecodeErrors: the value to set for report decode errors |
| * This method is asynchronous | ||
| * | ||
| * @param[in] sourceId : The source id. Value should be set to the MediaSource.id returned after attachSource() | ||
| * @param[in] reportDecodeErrors : The desired immediate output mode on the sink |
There was a problem hiding this comment.
The parameter description is incorrect. It states "The desired immediate output mode on the sink" but should state something like "The desired report decode errors mode on the sink" or similar to accurately describe the reportDecodeErrors parameter.
| * @param[in] reportDecodeErrors : The desired immediate output mode on the sink | |
| * @param[in] reportDecodeErrors : The desired report decode errors mode on the sink |
| } | ||
| else | ||
| { | ||
| RIALTO_SERVER_LOG_DEBUG("Pending an report_decode_errors, decoder is NULL"); |
There was a problem hiding this comment.
Grammar error in the log message. It should be "Pending a report_decode_errors" instead of "Pending an report_decode_errors" since "report" starts with a consonant sound.
| RIALTO_SERVER_LOG_DEBUG("Pending an report_decode_errors, decoder is NULL"); | |
| RIALTO_SERVER_LOG_DEBUG("Pending a report_decode_errors, decoder is NULL"); |
418abb7 to
50520a8
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 25 changed files in this pull request and generated 25 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| bool MediaPipelineService::setReportDecodeErrors(int sessionId, int32_t sourceId, bool reportDecodeErrors) | ||
| { | ||
| RIALTO_SERVER_LOG_INFO("MediaPipelineService requested to setReportDecodeErrors, session id: %d", sessionId); | ||
|
|
||
| std::lock_guard<std::mutex> lock{m_mediaPipelineMutex}; | ||
| auto mediaPipelineIter = m_mediaPipelines.find(sessionId); | ||
| if (mediaPipelineIter == m_mediaPipelines.end()) | ||
| { | ||
| RIALTO_SERVER_LOG_ERROR("Session with id: %d does not exists", sessionId); | ||
| return false; | ||
| } | ||
| return mediaPipelineIter->second->setReportDecodeErrors(sourceId, reportDecodeErrors); | ||
| } |
There was a problem hiding this comment.
The new setReportDecodeErrors method is missing unit test coverage. Tests should be added similar to the existing setImmediateOutput tests to verify both success and failure cases.
| bool MediaPipelineService::getQueuedFrames(int sessionId, int32_t sourceId, uint32_t &queuedFrames) | ||
| { | ||
| RIALTO_SERVER_LOG_INFO("MediaPipelineService requested to getQueuedFrames, session id: %d", sessionId); | ||
|
|
||
| std::lock_guard<std::mutex> lock{m_mediaPipelineMutex}; | ||
| auto mediaPipelineIter = m_mediaPipelines.find(sessionId); | ||
| if (mediaPipelineIter == m_mediaPipelines.end()) | ||
| { | ||
| RIALTO_SERVER_LOG_ERROR("Session with id: %d does not exists", sessionId); | ||
| return false; | ||
| } | ||
| return mediaPipelineIter->second->getQueuedFrames(sourceId, queuedFrames); | ||
| } |
There was a problem hiding this comment.
The new getQueuedFrames method is missing unit test coverage. Tests should be added to verify both success and failure cases.
| bool MediaPipelineServerInternal::setReportDecodeErrors(int32_t sourceId, bool reportDecodeErrors) | ||
| { | ||
| RIALTO_SERVER_LOG_DEBUG("entry:"); | ||
|
|
||
| bool result; | ||
| auto task = [&]() { result = setReportDecodeErrorsInternal(sourceId, reportDecodeErrors); }; | ||
|
|
||
| m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task); | ||
| return result; | ||
| } | ||
|
|
||
| bool MediaPipelineServerInternal::setReportDecodeErrorsInternal(int32_t sourceId, bool reportDecodeErrors) | ||
| { | ||
| if (!m_gstPlayer) | ||
| { | ||
| RIALTO_SERVER_LOG_ERROR("Failed - Gstreamer player has not been loaded"); | ||
| return false; | ||
| } | ||
| auto sourceIter = std::find_if(m_attachedSources.begin(), m_attachedSources.end(), | ||
| [sourceId](const auto &src) { return src.second == sourceId; }); | ||
| if (sourceIter == m_attachedSources.end()) | ||
| { | ||
| RIALTO_SERVER_LOG_ERROR("Failed - Source not found"); | ||
| return false; | ||
| } | ||
|
|
||
| return m_gstPlayer->setReportDecodeErrors(sourceIter->first, reportDecodeErrors); | ||
| } |
There was a problem hiding this comment.
The new setReportDecodeErrors and setReportDecodeErrorsInternal methods are missing unit test coverage. Tests should be added to verify the threading model, source validation, and error handling.
| * | ||
| * This method is sychronous, it gets the queued frames property | ||
| * | ||
| * @param[in] sourceId : The source id. Value should be get to the MediaSource.id returned after attachSource() |
There was a problem hiding this comment.
Spelling error in parameter description: "get" should be "set" (copy-paste error from the getter above).
| * @param[in] sourceId : The source id. Value should be get to the MediaSource.id returned after attachSource() | |
| * @param[in] sourceId : The source id. Value should be set to the MediaSource.id returned after attachSource() |
| // check the result | ||
| if (ipcController->Failed()) | ||
| { | ||
| RIALTO_CLIENT_LOG_ERROR("failed to get immediate-output due to '%s'", ipcController->ErrorText().c_str()); |
There was a problem hiding this comment.
Error message is incorrect: This function gets queued frames, not immediate-output. The error message should be "failed to get queued frames due to '%s'".
| RIALTO_CLIENT_LOG_ERROR("failed to get immediate-output due to '%s'", ipcController->ErrorText().c_str()); | |
| RIALTO_CLIENT_LOG_ERROR("failed to get queued frames due to '%s'", ipcController->ErrorText().c_str()); |
| bool MediaPipelineServerInternal::getQueuedFrames(int32_t sourceId, uint32_t &queuedFrames) | ||
| { | ||
| RIALTO_SERVER_LOG_DEBUG("entry:"); | ||
|
|
||
| bool result; | ||
| auto task = [&]() { result = getQueuedFramesInternal(sourceId, queuedFrames); }; | ||
|
|
||
| m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task); | ||
| return result; | ||
| } | ||
|
|
||
| bool MediaPipelineServerInternal::getQueuedFramesInternal(int32_t sourceId, uint32_t &queuedFrames) | ||
| { | ||
| if (!m_gstPlayer) | ||
| { | ||
| RIALTO_SERVER_LOG_ERROR("Failed - Gstreamer player has not been loaded"); | ||
| return false; | ||
| } | ||
| auto sourceIter = std::find_if(m_attachedSources.begin(), m_attachedSources.end(), | ||
| [sourceId](const auto &src) { return src.second == sourceId; }); | ||
| if (sourceIter == m_attachedSources.end()) | ||
| { | ||
| RIALTO_SERVER_LOG_ERROR("Failed - Source not found"); | ||
| return false; | ||
| } | ||
| return m_gstPlayer->getQueuedFrames(sourceIter->first, queuedFrames); | ||
| } |
There was a problem hiding this comment.
The new getQueuedFrames and getQueuedFramesInternal methods are missing unit test coverage. Tests should be added to verify the threading model, source validation, and error handling.
| bool MediaPipeline::setReportDecodeErrors(int32_t sourceId, bool reportDecodeErrors) | ||
| { | ||
| return m_mediaPipelineIpc->setReportDecodeErrors(sourceId, reportDecodeErrors); | ||
| } | ||
|
|
||
| bool MediaPipeline::getQueuedFrames(int32_t sourceId, uint32_t &queuedFrames) | ||
| { | ||
| return m_mediaPipelineIpc->getQueuedFrames(sourceId, queuedFrames); | ||
| } |
There was a problem hiding this comment.
The new setReportDecodeErrors and getQueuedFrames methods are missing unit test coverage. Tests should be added to verify the forwarding to the IPC layer.
| /** | ||
| * @brief Sets the "Report Decode Error" property for this source. | ||
| * | ||
| * @param[in] mediaSourceType : The media source type | ||
| * @param[in] reportDecodeErrors : Set report decode error | ||
| * | ||
| * @retval true on success. | ||
| */ | ||
| virtual bool setReportDecodeErrors(const MediaSourceType &mediaSourceType, bool reportDecodeErrors) = 0; | ||
|
|
||
| /** | ||
| * @brief Gets the queued frames for this source. | ||
| * | ||
| * @param[in] mediaSourceType : The media source type | ||
| * @param[out] queuedFrames : Get queued frames mode on the decoder | ||
| * | ||
| * @retval true on success. | ||
| */ | ||
| virtual bool getQueuedFrames(const MediaSourceType &mediaSourceType, uint32_t &queuedFrames) = 0; | ||
|
|
There was a problem hiding this comment.
The GstGenericPlayerMock is missing MOCK_METHOD declarations for the new setReportDecodeErrors and getQueuedFrames methods. These need to be added to maintain consistency with the interface and enable proper unit testing.
| bool setReportDecodeErrors(int32_t sourceId, bool reportDecodeErrors) override; | ||
|
|
||
| bool getQueuedFrames(int32_t sourceId, uint32_t &queuedFrames) override; | ||
|
|
There was a problem hiding this comment.
The MediaPipelineServerInternalMock is missing MOCK_METHOD declarations for the new setReportDecodeErrors and getQueuedFrames methods. These need to be added after the setImmediateOutput/getImmediateOutput methods to maintain consistency with the interface and enable proper unit testing.
| bool GstGenericPlayer::setReportDecodeErrors(bool reportDecodeErrors) | ||
| { | ||
| bool result{false}; | ||
| GstElement *decoder = getDecoder(MediaSourceType::VIDEO); |
There was a problem hiding this comment.
The implementation hardcodes MediaSourceType::VIDEO, but the public API accepts a mediaSourceType parameter. This creates an inconsistency where the caller can specify any source type, but it will always be applied to the VIDEO decoder. Either the implementation should respect the mediaSourceType parameter, or the API should not accept it at all.
| bool GstGenericPlayer::setReportDecodeErrors(bool reportDecodeErrors) | |
| { | |
| bool result{false}; | |
| GstElement *decoder = getDecoder(MediaSourceType::VIDEO); | |
| bool GstGenericPlayer::setReportDecodeErrors(MediaSourceType mediaSourceType, bool reportDecodeErrors) | |
| { | |
| bool result{false}; | |
| GstElement *decoder = getDecoder(mediaSourceType); |
Summary: 'queued_buffers' property missing from RialtoMSEVideoSink
Type: Feature
Test Plan: UT/CT, Fullstack
Jira: RDKEMW-12692
50520a8 to
d704fc2
Compare
|
I have read the CLA Document and I hereby sign the CLA |
|
tests/componenttests/server/tests/mediaPipeline/PipelinePropertyTest.cpp:350:0: style: The function 'setReportDecodeErrorsFailure' is never used. [unusedFunction] |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 62 out of 62 changed files in this pull request and generated 17 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| struct SetReportDecodeErrors | ||
| { | ||
| using RequestType = ::firebolt::rialto::SetReportDecodeErrorsRequest; | ||
| using ResponseType = ::firebolt::rialto::SetReportDecodeErrorsResponse; | ||
| using Stub = ::firebolt::rialto::MediaPipelineModule_Stub; | ||
| static constexpr auto m_kFunction{&Stub::setReportDecodeErrors}; | ||
| }; | ||
|
|
||
| struct GetQueuedFrames | ||
| { | ||
| using RequestType = ::firebolt::rialto::GetQueuedFramesRequest; | ||
| using ResponseType = ::firebolt::rialto::GetQueuedFramesResponse; | ||
| using Stub = ::firebolt::rialto::MediaPipelineModule_Stub; | ||
| static constexpr auto m_kFunction{&Stub::getQueuedFrames}; | ||
| }; |
There was a problem hiding this comment.
ActionTraits::SetReportDecodeErrors uses SetReportDecodeErrorsRequest/Response, but the proto currently defines ReportDecodeErrorsRequest/Response. Align these types (either by renaming the proto messages or updating the trait).
| constexpr bool kReportDecodeErrorsVal{false}; | ||
| constexpr bool kQueuedFramesVal{123}; |
There was a problem hiding this comment.
kQueuedFramesVal is declared as bool but used as a queued-frame count (set to 123 and written into a uint32_t &). This truncates the test value and can mask issues; it should be a uint32_t constant.
| { | ||
| firebolt::rialto::SetReportDecodeErrorsRequest request; | ||
| firebolt::rialto::SetReportDecodeErrorsResponse response; | ||
|
|
||
| request.set_session_id(kHardcodedSessionId); | ||
| request.set_immediate_output(kReportDecodeErrorsVal); | ||
|
|
||
| m_service->setReportDecodeErrors(m_controllerMock.get(), &request, &response, m_closureMock.get()); |
There was a problem hiding this comment.
These helpers use SetReportDecodeErrorsRequest/Response and set an immediate_output field, but the proto defines ReportDecodeErrorsRequest with a report_decode_errors field. As written, this won't compile and also won't exercise the correct request field; update the request/response types and set report_decode_errors (and source_id if the other tests do).
| uint32_t queuedFrames; | ||
| mainThreadWillEnqueueTaskAndWait(); | ||
| EXPECT_CALL(*m_gstPlayerMock, getQueuedFrames(_, _)).WillOnce(DoAll(SetArgReferee<1>(123), Return(true))); | ||
| EXPECT_TRUE(m_mediaPipeline->getQueuedFrames(videoSourceId, queuedFrames)); | ||
| EXPECT_EQ(queuedFrames, true); | ||
|
|
||
| mainThreadWillEnqueueTaskAndWait(); | ||
| EXPECT_CALL(*m_gstPlayerMock, getQueuedFrames(_, _)).WillOnce(DoAll(SetArgReferee<1>(123), Return(true))); | ||
| EXPECT_TRUE(m_mediaPipeline->getQueuedFrames(videoSourceId, queuedFrames)); | ||
| EXPECT_EQ(queuedFrames, false); | ||
| } |
There was a problem hiding this comment.
The test sets queuedFrames to 123 via the mock, but then compares it to true/false. This will fail (123 != true) and doesn't validate the correct behavior. Compare against the expected numeric values (and set different values for the two calls if you want to test both cases).
| message ReportDecodeErrorsRequest { | ||
| optional int32 session_id = 1 [default = -1]; | ||
| optional int32 source_id = 2 [default = -1]; | ||
| optional bool report_decode_errors = 3 [default = false]; | ||
| } | ||
|
|
||
| message ReportDecodeErrorsResponse { |
There was a problem hiding this comment.
The newly added proto messages are named ReportDecodeErrorsRequest/Response, but the rpc is setReportDecodeErrors and the rest of this proto uses the SetXxxRequest/Response naming convention (e.g., SetImmediateOutputRequest). This mismatch is already reflected in the tests/helpers referencing SetReportDecodeErrorsRequest, causing compile failures; rename the messages (or update all call sites) so the API is consistent end-to-end.
| message ReportDecodeErrorsRequest { | |
| optional int32 session_id = 1 [default = -1]; | |
| optional int32 source_id = 2 [default = -1]; | |
| optional bool report_decode_errors = 3 [default = false]; | |
| } | |
| message ReportDecodeErrorsResponse { | |
| message SetReportDecodeErrorsRequest { | |
| optional int32 session_id = 1 [default = -1]; | |
| optional int32 source_id = 2 [default = -1]; | |
| optional bool report_decode_errors = 3 [default = false]; | |
| } | |
| message SetReportDecodeErrorsResponse { |
| if (m_context.pipeline) | ||
| { | ||
| RIALTO_SERVER_LOG_DEBUG("Pipeline not available yet - cannot apply report_decode_errors setting"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
The pipeline check is inverted: if (m_context.pipeline) currently logs 'Pipeline not available yet' and returns, which prevents applying the setting when the pipeline actually exists. This should only early-return when the pipeline is not available, and should call m_player.setReportDecodeErrors(...) when it is.
| void GenericTasksTestsBase::shouldSetReportDecodeErrors() | ||
| { | ||
| EXPECT_CALL(testContext->m_gstPlayer, setReportDecodeErrors()).WillOnce(Return(true)); | ||
| } |
There was a problem hiding this comment.
shouldSetReportDecodeErrors() sets an expectation on setReportDecodeErrors() with no arguments, but the mocked method takes a bool reportDecodeErrors parameter. This will not compile; update the expectation to include the expected bool value (and align with the task trigger).
| void MediaPipelineServiceTests::getQueuedFramesShouldSucceed() | ||
| { | ||
| uint32_t queuedFr; | ||
| EXPECT_TRUE(m_sut->getQueuedFrames(kSessionId, kSourceId, queuedFr)); | ||
| EXPECT_TRUE(immOp); | ||
| } |
There was a problem hiding this comment.
getQueuedFramesShouldSucceed() references immOp, which is not declared in this function (likely a copy/paste from getImmediateOutputShouldSucceed). This will not compile and also doesn't validate the returned queued frame count; assert on queuedFr (e.g., expected 123) instead.
| ::firebolt::rialto::SetReportDecodeErrorsRequest createSetReportDecodeErrorsRequest(int sessionId, int sourceId, | ||
| bool reportDecodeErrors); | ||
| ::firebolt::rialto::GetQueuedFramesRequest createGetQueuedFramesRequest(int sessionId, int sourceId); |
There was a problem hiding this comment.
This header declares/returns ::firebolt::rialto::SetReportDecodeErrorsRequest, but the proto defines ReportDecodeErrorsRequest (and the service signature uses ReportDecodeErrorsRequest). This mismatch will break compilation; update the builder to use the actual generated proto type (or rename the proto message to match the builder).
| TEST_F(GstGenericPlayerPrivateTest, shouldFailToSetReportDecodeErrorsIfSinkIsNull) | ||
| { | ||
| EXPECT_CALL(*m_glibWrapperMock, gObjectGetStub(_, StrEq(kVideoSinkStr), _)) | ||
| .WillOnce(Invoke( | ||
| [&](gpointer object, const gchar *first_property_name, void *element) | ||
| { | ||
| GstElement **elementPtr = reinterpret_cast<GstElement **>(element); | ||
| *elementPtr = nullptr; | ||
| })); | ||
| EXPECT_FALSE(m_sut->setReportDecodeErrors()); | ||
| } | ||
|
|
||
| TEST_F(GstGenericPlayerPrivateTest, shouldFailToSetReportDecodeErrorsIfPropertyDoesntExist) | ||
| { | ||
| expectGetDecoder(m_element); | ||
|
|
||
| expectPropertyDoesntExist(m_glibWrapperMock, m_gstWrapperMock, m_realElement, kReportDecodeErrorsStr); | ||
| EXPECT_CALL(*m_gstWrapperMock, gstObjectUnref(m_realElement)).Times(1); | ||
| EXPECT_FALSE(m_sut->setReportDecodeErrors()); | ||
| } | ||
|
|
||
| TEST_F(GstGenericPlayerPrivateTest, shouldSetReportDecodeErrors) | ||
| { | ||
| expectGetDecoder(m_element); | ||
|
|
||
| expectSetProperty(m_glibWrapperMock, m_gstWrapperMock, m_realElement, kReportDecodeErrorsStr, true); | ||
| EXPECT_CALL(*m_gstWrapperMock, gstObjectUnref(m_realElement)).Times(1); | ||
| EXPECT_TRUE(m_sut->setReportDecodeErrors()); |
There was a problem hiding this comment.
These new tests call m_sut->setReportDecodeErrors() with no arguments, but IGstGenericPlayerPrivate::setReportDecodeErrors was added with a bool reportDecodeErrors parameter. As written, this won't compile; pass the expected bool value (and adjust the expectations accordingly).
|
Hi @Koky2701 : Please use the name "Comcast Cable Communications Management, LLC" for the Comcast company name in the 4 files: SetReportDecodeErrorsTest.cpp (3 files) and GetQueuedFramesTest.cpp. Thank you. |
1fe58a5 to
b3811c1
Compare
|
tests/componenttests/server/tests/mediaPipeline/PipelinePropertyTest.cpp:350:0: style: The function 'setReportDecodeErrorsFailure' is never used. [unusedFunction] |
b3811c1 to
40ff73a
Compare
|
tests/componenttests/server/tests/mediaPipeline/PipelinePropertyTest.cpp:350:0: style: The function 'setReportDecodeErrorsFailure' is never used. [unusedFunction] |
a33e411 to
9daca68
Compare
9daca68 to
5be2aba
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 64 out of 64 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| void MediaPipelineServiceTests::mediaPipelineWillGetQueuedFrames() | ||
| { | ||
| EXPECT_CALL(m_mediaPipelineMock, getQueuedFrames(_, _)).WillOnce(DoAll(SetArgReferee<1>(123), Return(true))); | ||
| } | ||
|
|
There was a problem hiding this comment.
This expectation hard-codes 123 when a kQueuedFrames constant already exists in this fixture. Using the constant avoids duplication and keeps the test aligned if the value changes.
| ::google::protobuf::Closure *done) | ||
| { | ||
| RIALTO_SERVER_LOG_DEBUG("entry:"); | ||
| uint32_t queuedFramesNumber; |
There was a problem hiding this comment.
queuedFramesNumber is declared without an initial value. Even though it’s only used on the success path, initializing it (e.g., to 0) makes the code more robust against accidental misuse and can avoid static-analysis warnings about potentially uninitialized output values.
| uint32_t queuedFramesNumber; | |
| uint32_t queuedFramesNumber{0}; |
| .WillOnce(DoAll(SetArgReferee<1>(123), Return(true))); | ||
| uint32_t QueuedFrames; | ||
| EXPECT_TRUE(m_mediaPipeline->getQueuedFrames(m_kSourceId, QueuedFrames)); | ||
| EXPECT_EQ(kExpectedQueuedFrames, QueuedFrames); |
There was a problem hiding this comment.
Local variable QueuedFrames uses UpperCamelCase, which is inconsistent with surrounding lowerCamelCase variable naming in tests (e.g., queuedFrames). Renaming improves readability and consistency.
5be2aba to
19f5878
Compare
Summary: Pending was not used.
Type: Fix
Test Plan: UT/CT, Fullstack
Jira: RDKEMW-12692
19f5878 to
fb0f618
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 63 out of 63 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * This method is synchronous, it gets the queued frames property | ||
| * | ||
| * @param[in] sourceId : The source id. Value should be set to the MediaSource.id returned after attachSource() | ||
| * @param[out] queuedFrames : Get queued frames on the decoder |
There was a problem hiding this comment.
The documentation says "Get queued frames on the decoder" but this should be more clear about the parameter direction. It should read "The number of queued frames on the decoder" or "Returns the number of queued frames on the decoder" to match the style of similar getter documentation in this interface.
| * @param[out] queuedFrames : Get queued frames on the decoder | |
| * @param[out] queuedFrames : The number of queued frames on the decoder |
| * This method is synchronous, it gets the queued frames property | ||
| * | ||
| * @param[in] sourceId : The source id. Value should be set to the MediaSource.id returned after attachSource() | ||
| * @param[out] queuedFrames : Get queued frames on the decoder |
There was a problem hiding this comment.
The documentation says "Get queued frames on the decoder" but should be more descriptive for an output parameter. It should read "The number of queued frames on the decoder" or "Returns the number of queued frames on the decoder" to match the documentation style for similar getter methods.
| * @param[out] queuedFrames : Get queued frames on the decoder | |
| * @param[out] queuedFrames : The number of queued frames on the decoder |
| @@ -333,7 +337,6 @@ void SetupElement::execute() const | |||
| { | |||
| m_gstWrapper->gstBaseParseSetPtsInterpolation(GST_BASE_PARSE(m_element), FALSE); | |||
| } | |||
There was a problem hiding this comment.
This deletion of a blank line appears to be an unintentional change unrelated to the feature being added. The blank line separation between the conditional block and the gstObjectUnref call improves code readability and should be retained.
| } | |
| } |
| * If not stated otherwise in this file or this component's LICENSE file the | ||
| * following copyright and licenses apply: | ||
| * | ||
| * Copyright 2026 Sky UK |
There was a problem hiding this comment.
The copyright year is inconsistent across the new files. This file has "Copyright 2026 Sky UK" while other new files in this PR have "Copyright 2025 Sky UK" and "Copyright 2024 Sky UK". Since the PR is being created in early 2025 (based on context), the copyright year should be "2025" to match other recently created files in the PR.
| * Copyright 2026 Sky UK | |
| * Copyright 2025 Sky UK |
| message ReportDecodeErrorsResponse { | ||
| } | ||
|
|
||
|
|
There was a problem hiding this comment.
There is an extra blank line here that is inconsistent with the formatting of other message definitions in this file. Message pairs (Request/Response) should have only one blank line between them and the next message, as seen with other definitions like SetImmediateOutputResponse and getImmediateOutput.
| * If not stated otherwise in this file or this component's LICENSE file the | ||
| * following copyright and licenses apply: | ||
| * | ||
| * Copyright 2024 Sky UK |
There was a problem hiding this comment.
The copyright year "2024" is inconsistent with other new test files in this PR that use "2025". Since this is a new file being added in early 2025, it should have "Copyright 2025 Sky UK" to match files like SetReportDecodeErrorsTest.cpp and GetQueuedFramesTest.cpp in the same directory.
|
Coverage statistics of your commit: |
a0c4f24 to
eea15c5
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 63 out of 63 changed files in this pull request and generated 10 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| TEST_F(GstGenericPlayerTest, shouldFailToGetQueuedFramesInPlayingStateIfMediaTypeWrong) | ||
| { | ||
| setPipelineState(GST_STATE_PLAYING); | ||
|
|
||
| uint32_t queuedFrames; | ||
| EXPECT_FALSE(m_sut->getQueuedFrames(MediaSourceType::UNKNOWN, queuedFrames)); | ||
| } |
There was a problem hiding this comment.
This test calls m_sut->getQueuedFrames(MediaSourceType::UNKNOWN, queuedFrames), but GstGenericPlayer/IGstGenericPlayer currently expose getQueuedFrames(uint32_t&) only. This is a signature mismatch that will fail compilation. Update the test to match the final API (and add media-type validation coverage if the API is updated to accept MediaSourceType).
| void SetReportDecodeErrors::execute() const | ||
| { | ||
| RIALTO_SERVER_LOG_DEBUG("Executing SetReportDecodeErrors for %s source", common::convertMediaSourceType(m_type)); | ||
|
|
There was a problem hiding this comment.
The new SetReportDecodeErrors task unconditionally writes pendingReportDecodeErrorsForVideo regardless of m_type. This differs from SetImmediateOutput (which rejects non-video types) and could accidentally apply the setting when called for AUDIO/UNKNOWN. Gate this logic on m_type == MediaSourceType::VIDEO (and log/return false for other types) to keep per-source behavior correct.
| if (MediaSourceType::VIDEO != m_type) | |
| { | |
| RIALTO_SERVER_LOG_WARN("SetReportDecodeErrors is only valid for VIDEO sources (got %s)", | |
| common::convertMediaSourceType(m_type)); | |
| return; | |
| } |
| int videoSourceId = attachSource(firebolt::rialto::MediaSourceType::VIDEO, "video/h264"); | ||
| mainThreadWillEnqueueTaskAndWait(); | ||
| EXPECT_CALL(*m_gstPlayerMock, getQueuedFrames(_, _)).WillOnce(Return(false)); | ||
| uint32_t queuedFrames; | ||
| EXPECT_FALSE(m_mediaPipeline->getQueuedFrames(videoSourceId, queuedFrames)); | ||
| } |
There was a problem hiding this comment.
The expectations for m_gstPlayerMock->getQueuedFrames(_, _) assume a 2-argument API, but IGstGenericPlayer::getQueuedFrames is currently declared with a single uint32_t& out-param. This will fail to compile once the mock/interface are aligned. Update this test to match the final getQueuedFrames signature (and verify the correct media source is used if a MediaSourceType parameter is added).
| if (mediaPipelineIter == m_mediaPipelines.end()) | ||
| { | ||
| RIALTO_SERVER_LOG_ERROR("Session with id: %d does not exists", sessionId); | ||
| return false; |
There was a problem hiding this comment.
Log message grammar: "does not exists" should be "does not exist".
| { | ||
| RIALTO_SERVER_LOG_ERROR("Session with id: %d does not exists", sessionId); | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Log message grammar: "does not exists" should be "does not exist".
| * @brief Sets the "Report Decode Errors" property for this source. | ||
| * | ||
| * This method is asynchronous | ||
| * | ||
| * @param[in] sourceId : The source id. Value should be set to the MediaSource.id returned after attachSource() | ||
| * @param[in] reportDecodeErrors : The desired Set Report Decode Errors mode on the sink | ||
| * | ||
| * @retval true on success. | ||
| */ | ||
| bool setReportDecodeErrorsInternal(int32_t sourceId, bool reportDecodeErrors); |
There was a problem hiding this comment.
The Doxygen for setReportDecodeErrorsInternal says the setting is applied "on the sink", but the implementation applies report_decode_errors on the decoder element. Please update the comment to reflect where the property is set (decoder) to avoid misleading API documentation.
| MOCK_METHOD(bool, getImmediateOutput, (const MediaSourceType &mediaSourceType, bool &immediateOutput), (override)); | ||
| MOCK_METHOD(bool, setReportDecodeErrors, (const MediaSourceType &mediaSourceType, bool reportDecodeErrors), | ||
| (override)); | ||
| MOCK_METHOD(bool, getQueuedFrames, (const MediaSourceType &mediaSourceType, uint32_t &queuedFrames), (override)); | ||
| MOCK_METHOD(bool, getStats, |
There was a problem hiding this comment.
getQueuedFrames mock signature includes a MediaSourceType argument, but IGstGenericPlayer::getQueuedFrames is declared as getQueuedFrames(uint32_t&). This will not compile because the method marked override doesn't match the interface. Update the mock (and any expectations) to match the interface, or update the interface/implementation to accept MediaSourceType consistently.
| RIALTO_SERVER_LOG_ERROR("Failed - Source not found"); | ||
| return false; | ||
| } | ||
| return m_gstPlayer->getQueuedFrames(queuedFrames); |
There was a problem hiding this comment.
getQueuedFramesInternal validates the sourceId but then ignores the resolved media source type (sourceIter->first) when calling the gst player. As written, it will always query the player's default (currently VIDEO) queued frames even if the sourceId refers to a different source, and it also won't compile if the gst player API expects a media type. Use the resolved media type when calling into m_gstPlayer, or explicitly reject non-video sources here.
| return m_gstPlayer->getQueuedFrames(queuedFrames); | |
| return m_gstPlayer->getQueuedFrames(sourceIter->first, queuedFrames); |
| void MediaPipelineModuleServiceTests::sendGetQueuedFramesRequestAndReceiveFail() | ||
| { | ||
| firebolt::rialto::GetQueuedFramesRequest request; | ||
| firebolt::rialto::GetQueuedFramesResponse response; | ||
|
|
||
| request.set_session_id(kHardcodedSessionId); | ||
|
|
||
| m_service->getQueuedFrames(m_controllerMock.get(), &request, &response, m_closureMock.get()); | ||
| } |
There was a problem hiding this comment.
GetQueuedFramesRequest includes a source_id field, but this test request only sets session_id, so it doesn't validate correct per-source routing. Set source_id and update the service mock expectation to match, otherwise a regression where source_id is ignored would still pass.
| * @param[out] queuedFrames : Get queued frames mode on the decoder | ||
| * | ||
| * @retval true on success. | ||
| */ | ||
| virtual bool getQueuedFrames(uint32_t &queuedFrames) = 0; |
There was a problem hiding this comment.
IGstGenericPlayer::getQueuedFrames is declared with only an output parameter, but other updated code in this PR (e.g., mocks/tests and MediaPipelineServerInternal) treats it as a per-source operation that needs a MediaSourceType/source context. This inconsistency will cause override/signature mismatches and makes it unclear which source the queued frames belong to. Align the API across interface, implementation, and callers (either add a MediaSourceType parameter like other per-source getters, or update mocks/tests/callers to the 1-arg form and explicitly validate that only VIDEO sources are supported).
| * @param[out] queuedFrames : Get queued frames mode on the decoder | |
| * | |
| * @retval true on success. | |
| */ | |
| virtual bool getQueuedFrames(uint32_t &queuedFrames) = 0; | |
| * @param[in] mediaSourceType : The media source type | |
| * @param[out] queuedFrames : Get queued frames mode on the decoder | |
| * | |
| * @retval true on success. | |
| */ | |
| virtual bool getQueuedFrames(const MediaSourceType &mediaSourceType, uint32_t &queuedFrames) = 0; |
eea15c5 to
31c31c5
Compare
31c31c5 to
c867d8e
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 63 out of 63 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * This method is asynchronous | ||
| * | ||
| * @param[in] sourceId : The source id. Value should be set to the MediaSource.id returned after attachSource() | ||
| * @param[in] queuedFrames : Number of queued frames | ||
| * | ||
| * @retval true on success. | ||
| */ | ||
| bool getQueuedFramesInternal(int32_t sourceId, uint32_t &queuedFrames); |
There was a problem hiding this comment.
Doxygen annotation marks queuedFrames as [in], but it is an output parameter (uint32_t &queuedFrames). Update the comment to [out] to avoid misleading API documentation.
| if (m_context.pendingReportDecodeErrorsForVideo.has_value()) | ||
| { | ||
| m_player.setReportDecodeErrors(); | ||
| } | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
pendingReportDecodeErrorsForVideo is only applied here when a subtitle sink exists and the video decoder handle is being set. If subtitles are not used, the pending report_decode_errors value may never be applied to the decoder. Consider applying setReportDecodeErrors() whenever the video decoder element is discovered (independent of subtitleSink/isVideoHandleSet).
| if (m_context.pendingReportDecodeErrorsForVideo.has_value()) | |
| { | |
| m_player.setReportDecodeErrors(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if (isVideoDecoder(*m_gstWrapper, m_element) && m_context.pendingReportDecodeErrorsForVideo.has_value()) | |
| { | |
| m_player.setReportDecodeErrors(); | |
| } |
| GstElement *decoder = getDecoder(MediaSourceType::VIDEO); | ||
| if (decoder) | ||
| { | ||
| RIALTO_SERVER_LOG_DEBUG("Set report decode errors to %s", reportDecodeErrors ? "TRUE" : "FALSE"); | ||
|
|
||
| if (m_glibWrapper->gObjectClassFindProperty(G_OBJECT_GET_CLASS(decoder), "report_decode_errors")) | ||
| { | ||
| gboolean reportDecodeErrorsGboolean{reportDecodeErrors ? TRUE : FALSE}; | ||
| m_glibWrapper->gObjectSet(decoder, "report_decode_errors", reportDecodeErrorsGboolean, nullptr); |
There was a problem hiding this comment.
PR description mentions report_decode_errors missing from RialtoMSEVideoSink, but the implementation sets/queries report_decode_errors on the VIDEO decoder element (getDecoder(MediaSourceType::VIDEO)). Please confirm whether the property is expected on the sink or decoder and adjust the element lookup accordingly to match the intended GStreamer element.
| RIALTO_SERVER_LOG_ERROR("Failed - Source not found"); | ||
| return false; | ||
| } | ||
|
|
There was a problem hiding this comment.
setReportDecodeErrorsInternal forwards the request based only on sourceId presence. Since the underlying implementation currently targets the video decoder, an AUDIO sourceId would still end up toggling the video decoder setting. Add a check that the matched source type is MediaSourceType::VIDEO (or otherwise handle per-type state) and fail for unsupported types.
| // setReportDecodeErrors currently targets the video decoder; reject unsupported source types | |
| if (sourceIter->first != MediaSourceType::VIDEO) | |
| { | |
| RIALTO_SERVER_LOG_ERROR("Failed - setReportDecodeErrors is supported only for video sources"); | |
| return false; | |
| } |
c867d8e to
fec5278
Compare
Summary: Redundant argument.
Type: Fix
Test Plan: UT/CT, Fullstack
Jira: RDKEMW-12692
fec5278 to
14d4efd
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 63 out of 63 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| stop(); | ||
|
|
||
| // Step 19: Destroy media session | ||
| // Step 18: Destroy media session |
There was a problem hiding this comment.
The comment on line 600 says "Step 18: Destroy media session" but was previously "Step 19: Destroy media session". This change appears to be incorrect since no steps were actually removed from the test - new functionality was added but the existing steps remain the same. The comment should remain as "Step 19" or the test should be updated to include the new property testing steps.
|
Coverage statistics of your commit: |
|
Coverage statistics of your commit: |
Summary: 'report_decode_errors' property missing from RialtoMSEVideoSink
Type: Feature
Test Plan: UT/CT, Fullstack
Jira: RDKEMW-12692